#include <casgidriver/CASgiDriverE.h>

// ***********************************************************************

// class EDROOMTopContext

// ***********************************************************************



	// CONSTRUCTORES***********************************************

CASgiDriver::EDROOMTopContext::EDROOMTopContext (CASgiDriver &act, uint16_t & EDROOMpVarVByteNumber, uint16_t & EDROOMpVarVDataLength, bool_t & EDROOMpVarVMessageCompleted, byte_t * EDROOMpVarVStringDataBurst, CPackListHandler & EDROOMpVarVTCPackList, CEDROOMPOOLCDBurst & EDROOMpPoolCDBurst, CEDROOMPOOLCDDataBurst & EDROOMpPoolCDDataBurst ):

	EDROOMcomponent(act)
	,Msg(EDROOMcomponent.Msg)
	,MsgBack(EDROOMcomponent.MsgBack)
	,SGIGround(EDROOMcomponent.SGIGround)
	, VByteNumber ( EDROOMpVarVByteNumber )
	, VDataLength ( EDROOMpVarVDataLength )
	, VMessageCompleted ( EDROOMpVarVMessageCompleted )
	, VStringDataBurst ( EDROOMpVarVStringDataBurst )
	, VTCPackList ( EDROOMpVarVTCPackList )
	, EDROOMPoolCDBurst ( EDROOMpPoolCDBurst )
	, EDROOMPoolCDDataBurst ( EDROOMpPoolCDDataBurst )
 {

}

CASgiDriver::EDROOMTopContext::EDROOMTopContext ( EDROOMTopContext &contex ):

	EDROOMcomponent(contex.EDROOMcomponent),
	Msg(contex.Msg),
	MsgBack(contex.MsgBack)
	,SGIGround(contex.SGIGround)
	, VByteNumber ( contex.VByteNumber )
	, VDataLength ( contex.VDataLength )
	, VMessageCompleted ( contex.VMessageCompleted )
	, VStringDataBurst ( contex.VStringDataBurst )
	, VTCPackList ( contex.VTCPackList )
	, EDROOMPoolCDBurst ( contex.EDROOMPoolCDBurst )
	, EDROOMPoolCDDataBurst ( contex.EDROOMPoolCDDataBurst )
 {

}

	// EDROOMSearchContextTrans********************************************

bool CASgiDriver::EDROOMTopContext::EDROOMSearchContextTrans(TEDROOMTransId &edroomCurrentTrans){

	bool edroomValidMsg=false; 

	 switch(Msg->signal){

		 case ( EDROOMSignalDestroy ): 

			 edroomValidMsg=true;
			 edroomCurrentTrans.distanceToContext = 0 ;
			 edroomCurrentTrans.localId = -1 ;
			 break;

	}

	return(edroomValidMsg);

}

	// Funciones Definidas por el usuario  ****************************

void	CASgiDriver::EDROOMTopContext::FBuildUpBurst()

 
 
{
	byte_t codeOfBurst=0;
	uint16_t i=0;
	uint16_t j=0;
	uint16_t nf=0;
	CPackHandler newEditPackHandler;
	uint16_t index=0;
 
	codeOfBurst = sgi_link_layer_get_code(VStringDataBurst);
	//Si VByteNumber es 0 es que es mensaje err?neo
	if ((VByteNumber) &&
			((MASK_BURST_A_SGI==codeOfBurst)	|| //DataBurst
					(MASK_BURST_D_SGI==codeOfBurst)   ||
					(MASK_BURST_C_SGI==codeOfBurst)))
	{
		CDDataBurst * ap_CDDataBurst = EDROOMPoolCDDataBurst.AllocData();
 
		// Build data burst to CASGI
		//copy header
		for (i=0;i<SGI_HEADER_LENGTH;i++)
		{
			ap_CDDataBurst->header[i]=VStringDataBurst[i];
		}
 
		//copy data
		ap_CDDataBurst->packList=VTCPackList;
		ap_CDDataBurst->packList.ToHeadPack();
		nf = sgi_link_layer_get_nf(ap_CDDataBurst->header);
		for (i=0;(i<nf) && (i<ap_CDDataBurst->packList.GetPackCounter());i++)
		{
			ap_CDDataBurst->packList.GetCurrentEditPack(newEditPackHandler);
			index=i*256+32;
			for (j=0;j<256;j++)
			{
				newEditPackHandler.WriteByte(j,VStringDataBurst[index+j]);
			}
			ap_CDDataBurst->packList.NextEditPack();
		}
 
		// reply
		Msg->reply(SRxDataBurst, ap_CDDataBurst, &EDROOMPoolCDDataBurst);
	}
	else if ((VByteNumber) &&
			((MASK_BURST_F_SGI==codeOfBurst) || //Burst
					(MASK_BURST_B_SGI==codeOfBurst) ||
					(MASK_BURST_E_SGI==codeOfBurst)))
	{
		CDBurst * ap_CDBurst = EDROOMPoolCDBurst.AllocData();
 
		// Build data burst to CASGI
		for (i=0;i<SGI_HEADER_LENGTH;i++)
		{
			ap_CDBurst->header[i]=VStringDataBurst[i];
		}
		// reply
		Msg->reply(SRxBurst, ap_CDBurst, &EDROOMPoolCDBurst);
	}
	else
	{
		Msg->reply(SNoAnswer);
	}
 
 
}



void	CASgiDriver::EDROOMTopContext::FCheckBytesReceived()

 
{
	int8_t offSet=0;
	byte_t codeOfBurst=0;
 
	if ((SGI_HEADER_LENGTH==VByteNumber) || (VDataLength==VByteNumber))
	{
 
		if (sgi_link_layer_check_crcs(VStringDataBurst,&offSet))
		{
 
			codeOfBurst = sgi_link_layer_get_code(VStringDataBurst+offSet);
			if ((MASK_BURST_A_SGI==codeOfBurst)	|| //DataBurst
					(MASK_BURST_D_SGI==codeOfBurst) ||
					(MASK_BURST_C_SGI==codeOfBurst))
			{
				VDataLength=SGI_HEADER_LENGTH+(sgi_link_layer_get_nf(VStringDataBurst+offSet)*256);
 
				if (VDataLength==VByteNumber)
				{
					VMessageCompleted=true;
				}
			}
			else if ((MASK_BURST_F_SGI==codeOfBurst) || //Burst
					(MASK_BURST_B_SGI==codeOfBurst)  ||
					(MASK_BURST_E_SGI==codeOfBurst))
			{
				VMessageCompleted=true;
			}
			else
			{
				VMessageCompleted=true;
				VByteNumber=0;
			}
		}
		else
		{
			VMessageCompleted=true;
			VByteNumber=0;
		}
	}
	else if (((!VDataLength) && (SGI_HEADER_LENGTH<VByteNumber)) ||
			((VDataLength) && (VDataLength<VByteNumber))	||
			(BUFFER_SIZE==VByteNumber))
	{
		VMessageCompleted=true;
		VByteNumber=0;
	}
 
 
}
 



void	CASgiDriver::EDROOMTopContext::FGetData()

 
 
{
 
	while ((bufferOfDevices[SGI_BUFFER].bytesWritten) && !(VMessageCompleted))
	{
		VStringDataBurst[VByteNumber]=bufferOfDevices[SGI_BUFFER].buffer[bufferOfDevices[SGI_BUFFER].readIndex++];
		if (bufferOfDevices[SGI_BUFFER].readIndex>=15000)
		{
			bufferOfDevices[SGI_BUFFER].readIndex=0;
		}
		VByteNumber++;
	
			Pr_IRQManager::DisableIRQ(UART_IRQ_NUM);
		bufferOfDevices[SGI_BUFFER].bytesWritten--;
		Pr_IRQManager::EnableIRQ(UART_IRQ_NUM);
		
		if (VByteNumber%32==0)
		{
			FCheckBytesReceived();
		}
	}
 
 
}
 



void	CASgiDriver::EDROOMTopContext::FInit()

{
	word16_t numPackets=32;
 
	globalPackListPool.AllocPackages(numPackets,VTCPackList);
}



void	CASgiDriver::EDROOMTopContext::FNotAnswer()

{
	Msg->reply(SNoAnswer);
 
}



void	CASgiDriver::EDROOMTopContext::FSendBurstToGround()

 
 
{
 
	CDBurst & varCDBurst = *(CDBurst *)Msg->data;
	uint8_t i=0;
	VByteNumber= 0;
	VMessageCompleted = false;
	VDataLength =0;
 
 
 
	
	Pr_IRQManager::DisableIRQ(UART_IRQ_NUM);
	clear_sgi_buffer();
	Pr_IRQManager::EnableIRQ(UART_IRQ_NUM);
	
 
	//Send to UART
	for (i=0;i<SGI_HEADER_LENGTH;i++)
	{
 
		sgi_uart_dev_putchar(varCDBurst.header[i]);
	}
 
	FWaitToResponse();
 
}
 
 



void	CASgiDriver::EDROOMTopContext::FSendDataBurstToGround()

 
 
{
	DEBUG("\n");
	uint16_t i=0;
	byte_t stringDataBurst[BUFFER_SIZE];
	CDDataBurst & varCDDataBurst = *(CDDataBurst *)Msg->data;
	uint8_t nf = sgi_link_layer_get_nf(varCDDataBurst.header);
	uint16_t numberOfBytes=SGI_HEADER_LENGTH+nf*256;
	VByteNumber= 0;
	VMessageCompleted = false;
	VDataLength =0;
 
 
	Pr_IRQManager::DisableIRQ(UART_IRQ_NUM);
	clear_sgi_buffer();
	Pr_IRQManager::EnableIRQ(UART_IRQ_NUM);
	//Copy Header...
	for (i=0; i<SGI_HEADER_LENGTH; i++)//cambiar por strncpy
	{
		stringDataBurst[i]=varCDDataBurst.header[i];
	}
 
	//...and now DataFrames
	PacketsToBytes(varCDDataBurst.packList,stringDataBurst,nf);
 
	//Send to Modem
	for (i=0;i<numberOfBytes;i++)
	{
 
		sgi_uart_dev_putchar(stringDataBurst[i]);
 
	}
 
	FWaitToResponse();
 
}
 



void	CASgiDriver::EDROOMTopContext::FWaitToResponse()

{
	uint16_t timeOfWaiting=0;
	float tRxTx= 0.5;//TODO: definir un tiempo m?ximo de espera para considerar que no hay respueta
 
	Pr_Time	interval(tRxTx); // Declare time var with an initial value in seconds
 
	//while (!(VMessageCompleted) && (timeOfWaiting <100000)  && (bufferOfDeviceIndex))//TODO: O m?todo similar que compare el paso del tiempo en el sistema
	while (!(VMessageCompleted) &&  (bufferOfDeviceIndex))//TODO: O m?todo similar que compare el paso del tiempo en el sistema
	{
		Pr_DelayIn(interval);
		timeOfWaiting++;
		FGetData();
	}
 
 
}



	//*****Pools

	//CEDROOMPOOLCDBurst

CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDBurst::CEDROOMPOOLCDBurst(unsigned int elemCount, CDBurst* pMem, TEDROOMBool * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDBurst)){;}

CDBurst *	CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDBurst::AllocData(){
	return(CDBurst*)CEDROOMProtectedMemoryPool::AllocData();
}

	//CEDROOMPOOLCDDataBurst

CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDDataBurst::CEDROOMPOOLCDDataBurst(unsigned int elemCount, CDDataBurst* pMem, TEDROOMBool * pMemMarks):CEDROOMProtectedMemoryPool(elemCount, pMem, pMemMarks, sizeof (CDDataBurst)){;}

CDDataBurst *	CASgiDriver::EDROOMTopContext::CEDROOMPOOLCDDataBurst::AllocData(){
	return(CDDataBurst*)CEDROOMProtectedMemoryPool::AllocData();
}



// ***********************************************************************

// class EDROOMTopState

// ***********************************************************************



	// CONSTRUCTOR*************************************************

CASgiDriver::EDROOMTopState::EDROOMTopState (CASgiDriver &act, CEDROOMMemory *pEDROOMMemory  ):
	  EDROOMTopContext( act , VByteNumber, VDataLength, VMessageCompleted, VStringDataBurst, VTCPackList,EDROOMPoolCDBurst,EDROOMPoolCDDataBurst )
	, VByteNumber ( 0 )
	, VDataLength ( 0 )
	, VMessageCompleted ( false )
	, VTCPackList (   )
	, EDROOMPoolCDBurst ( SIZE_OF_POOLS, pEDROOMMemory->poolCDBurst, pEDROOMMemory->poolMarkCDBurst)
	, EDROOMPoolCDDataBurst ( SIZE_OF_POOLS, pEDROOMMemory->poolCDDataBurst, pEDROOMMemory->poolMarkCDDataBurst)
{

}

	// EDROOMBehaviour**********************************************

void CASgiDriver::EDROOMTopState::EDROOMBehaviour(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans = EDROOMIllegada();

	do{

		switch(edroomCurrentTrans.localId){

			case(Init):
				FInit();
				edroomNextState = Listening;
				break;
			case(SendSignal):
				FSendBurstToGround();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( VMessageCompleted ){
					FBuildUpBurst();
					edroomCurrentTrans.localId = SendSignal_MessageReceived;
					edroomNextState = Listening;
				 } 
				else{
					FNotAnswer();
					edroomCurrentTrans.localId = SendSignal_NotAnswer;
					edroomNextState = Listening;
				 } 
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
			case(SendData):
				FSendDataBurstToGround();

				EDROOMcomponent.EDROOMTraceStateEntry();

				if( VMessageCompleted ){
					FBuildUpBurst();
					edroomCurrentTrans.localId = SendData_MessageReceived;
					edroomNextState = Listening;
				 } 
				else{
					FNotAnswer();
					edroomCurrentTrans.localId = SendData_NotAnswer;
					edroomNextState = Listening;
				 } 
				EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);
				break;
		}

		EDROOMcomponent.EDROOMTraceStateEntry();

		EDROOMcomponent.EDROOMTraceStateEntry();

		switch(edroomNextState){

			case(I):
				edroomCurrentTrans=EDROOMIllegada();
				break;

			case(Listening):
				edroomCurrentTrans=EDROOMListeningllegada();
				break;

		}

		EDROOMcomponent.EDROOMTraceStateExit();

		edroomCurrentState=edroomNextState;

	}while(Msg->signal != EDROOMSignalDestroy);

}



	// Inicio**********************************************

void CASgiDriver::EDROOMTopState::EDROOMInicio(){

edroomCurrentState=I;

}



//	 ***********************************************************************

//	 llegada SubEstado I

//	 ***********************************************************************



TEDROOMTransId CASgiDriver::EDROOMTopState::EDROOMIllegada(){

	TEDROOMTransId edroomCurrentTrans;

	edroomCurrentTrans.localId = Init;
	edroomCurrentTrans.distanceToContext = 0;
	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, 0);

	return(edroomCurrentTrans);

}



	// ***********************************************************************

	// llegada SubEstado Hoja Listening

	// ***********************************************************************



TEDROOMTransId CASgiDriver::EDROOMTopState::EDROOMListeningllegada(){

	TEDROOMTransId edroomCurrentTrans;

	int edroomValidMsg=false;

	do{

		EDROOMNuevoMens ();

		switch(Msg->signal){

			case (STxBurst): 

				 if ( *Msg->GetPInterface() == SGIGround) {

					edroomCurrentTrans.localId = SendSignal;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

			case (STxDataBurst): 

				 if ( *Msg->GetPInterface() == SGIGround) {

					edroomCurrentTrans.localId = SendData;
					edroomCurrentTrans.distanceToContext = 0 ;
					edroomValidMsg=true;
				 }

				break;

		};

		if (!edroomValidMsg) edroomValidMsg = EDROOMSearchContextTrans(edroomCurrentTrans);

	} while (!edroomValidMsg);

	EDROOMcomponent.EDROOMTraceTrans(edroomCurrentTrans, Msg->signal);

	return(edroomCurrentTrans);

}



